package com.coocaa.x.service.litedownloader2;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.coocaa.x.framework.app.CoocaaApplication;
import com.coocaa.x.framework.app.CoocaaService;
import com.coocaa.x.framework.data.JObject;
import com.coocaa.x.framework.utils.AsyncTask;
import com.coocaa.x.framework.utils.Cache;
import com.coocaa.x.framework.utils.LiteHandlerThread;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.framework.utils.Storage;
import com.coocaa.x.service.XServiceManager;
import com.coocaa.x.service.litedownloader2.aidl.DownloadTask;
import com.coocaa.x.service.litedownloader2.aidl.ILiteDownloadServiceListener;
import com.coocaa.x.service.litedownloader2.aidl.ILiteDownloaderService;
import com.coocaa.x.service.litepm.aidl.ILitePMInstallListener;
import com.coocaa.x.service.litepm.data.AppInfo;
import com.coocaa.x.service.litepm.data.InstallParams;
import com.duowan.mobile.netroid.Listener;
import com.duowan.mobile.netroid.NetroidError;
import com.duowan.mobile.netroid.toolbox.FileDownloader;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


/**
 * Created by lu on 15-6-17.
 */
public class LiteDownloaderServiceStub extends ILiteDownloaderService.Stub {


    private ILitePMInstallListener.Stub installListener = new ILitePMInstallListener.Stub() {
        @Override
        public void onInstallStart(String apkfile, AppInfo pkgname, final InstallParams params) throws RemoteException {

        }

        @Override
        public void onInstallEnd(String apkfile, AppInfo appInfo, int result, String extra, final InstallParams params) throws RemoteException {
            try {
                List<DownloadTask> tasks = getList();
                LogUtils.d("delete", "install end delete apkfile");
                if (tasks != null && tasks.size() > 0) {
                    for (DownloadTask task : tasks) {
                        if (task.save_path.equals(apkfile)) {
                            cancel(task);
                            break;
                        }
                    }
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };

    private static class TaskList extends JObject {
        public List<DownloadTask> tasks = new ArrayList<DownloadTask>();

        public TaskList() {

        }

        public TaskList(List<DownloadTask> tasks) {
            this.tasks = tasks;
        }
    }

    private static final String CONFIG_KEY = "lite_downloader2_tasklist";

    private class MyListener extends Listener<Void> {
        private DownloadTask task = null;

        public MyListener(DownloadTask task) {
            this.task = task;
        }

        @Override
        public void onPreExecute() {
            synchronized (callbacks) {
                for (final CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    AsyncTask.runOnThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                i.i.onStarted(task);
                            } catch (RemoteException e) {
                            }
                        }
                    });
                }
            }
        }

        @Override
        public void onError(final NetroidError error) {
            try {
                LogUtils.d("Luyx", "statusCode:" + error.networkResponse.statusCode + "msg:" + error.networkResponse.charset);
            } catch (Exception e) {
            }
//            if (error != null && error.networkResponse != null) {
//                if (error.networkResponse.statusCode == -1000) {
//                    synchronized (availableDownloadPath) {
//                        int pos = availableDownloadPath.indexOf(task.save_path.substring(0, task.save_path.lastIndexOf('/')));
//                        LogUtils.d("downloader", "pos:" + pos);
//                        if (pos == -1) {
//                            LogUtils.d("downloader", "nospc change from " + task.save_path + " to " + availableDownloadPath.get(0));
//                            task.save_path = availableDownloadPath.get(0);
//                            try {
//                                start(task);
//                                return;
//                            } catch (RemoteException e) {
//                                e.printStackTrace();
//                            }
//                        } else if (pos + 1 < availableDownloadPath.size()) {
//                            LogUtils.d("downloader", "nospc change from " + task.save_path + " to " + availableDownloadPath.get(pos + 1));
//                            task.save_path = availableDownloadPath.get(pos + 1);
//                            try {
//                                start(task);
//                                return;
//                            } catch (RemoteException e) {
//                                e.printStackTrace();
//                            }
//                        }
//                    }
//                }
//            }
            synchronized (callbacks) {
                for (final CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    AsyncTask.runOnThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (error != null && error.networkResponse != null) {
                                    i.i.onError(task, error.networkResponse.statusCode, error.networkResponse.charset);
                                } else
                                    i.i.onError(task, -100000, "unknow download error!");
                            } catch (RemoteException e) {
                            }
                        }
                    });
                }
            }
        }

        @Override
        public void onCancel() {
            dcCache.remove(task._getID());
            taskCache.remove(task._getID());
            try {
                XServiceManager.getLiteConfigService().saveStringConfig(CONFIG_KEY, new TaskList(taskCache.values()).toJSONString());
            } catch (RemoteException e) {
            }
            synchronized (callbacks) {
                for (final CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    AsyncTask.runOnThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                i.i.onCanceled(task);
                            } catch (RemoteException e) {
                            }
                        }
                    });
                }
            }
        }

        @Override
        public void onProgressChange(final long fileSize, final
        long downloadedSize) {
            final int percent = (int) (100 * downloadedSize / fileSize);
            synchronized (callbacks) {
                for (final CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    AsyncTask.runOnThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                i.i.onProgressUpdate(task, percent, fileSize, downloadedSize);
                            } catch (RemoteException e) {
                            }
                        }
                    });
                }
            }
        }

        @Override
        public void onSuccess(Void aVoid) {
            try {
                Runtime.getRuntime().exec("chmod -R 755 " + task.save_path);
            } catch (Exception e) {
            }
            CoocaaApplication.post(new Runnable() {
                @Override
                public void run() {
                    handleOnSuccessAction();
                }
            });
            synchronized (callbacks) {
                for (final CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    CoocaaApplication.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                i.i.onSuccess(task);
                            } catch (RemoteException e) {
                            }
                        }
                    });
                }
            }
        }

        private void handleOnSuccessAction() {
            if (task.action != null) {
                if (task.action.action_type == DownloadTask.DownloadTaskOnSuccessAction.ACTION_TYPE.OTHER) {
                    if (task.action.action_data.equals(DownloadTask.DownloadTaskOnSuccessAction.AUTO_INSTALL_ACTION)) {
                        String apk_file = task.action.params.get("apk_file");
                        if (apk_file != null && !apk_file.equals(""))
                            try {
                                InstallParams params = new InstallParams();
                                params.setFrom(InstallParams.INSTALL_FROM.COOCAA_MARKET);
                                XServiceManager.getLitePMService().install(apk_file, CoocaaApplication.isRoot(), params);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                    }
                } else {
                    Intent intent = new Intent();
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setPackage(task.action.pkg);
                    switch (task.action.action_type) {
                        case ACTION:
                            intent.setAction(task.action.action_data);
                            break;
                        case ACTIVITY:
                            intent.setClassName(task.action.pkg, task.action.action_data);
                            break;
                        case URI:
                            intent.setData(Uri.parse(task.action.action_data));
                            break;
                        default:
                            break;
                    }

                    Set<String> keys = task.action.params.keySet();
                    for (String key : keys)
                        intent.putExtra(key, task.action.params.get(key));
                    try {
                        mContext.startActivity(intent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private Context mContext = null;

    private Cache<String, DownloadTask> taskCache = new Cache<String, DownloadTask>();
    private Cache<String, FileDownloader.DownloadController> dcCache = new Cache<String, FileDownloader.DownloadController>();

    private List<CoocaaService.AIDLInterface<ILiteDownloadServiceListener>> callbacks = new ArrayList<CoocaaService.AIDLInterface<ILiteDownloadServiceListener>>();

//    private List<String> availableDownloadPath = new ArrayList<String>();

    public LiteDownloaderServiceStub(Context c) {
        CoocaaApplication.post(new Runnable() {
            @Override
            public void run() {
                String value = null;
                try {
                    value = XServiceManager.getLiteConfigService().getStringValue(CONFIG_KEY, "");
                    XServiceManager.getLitePMService().addInstallListener(installListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

                if (value != null && !value.equals("")) {
                    try {
                        TaskList tasks = JObject.parseJObject(value, TaskList.class);
                        for (DownloadTask task : tasks.tasks)
                            taskCache.add(task._getID(), task);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        mContext = c;
//        updateAvailableDownloadPath();
//
//        Storage.addListener(new Storage.IStorageListener() {
//            @Override
//            public void onStorageMounted(Storage.SDevice device) {
//                updateAvailableDownloadPath();
//            }
//
//            @Override
//            public void onStorageRemoved(Storage.SDevice device) {
//                updateAvailableDownloadPath();
//            }
//        });
    }

//    private void updateAvailableDownloadPath() {
//        synchronized (availableDownloadPath) {
//            availableDownloadPath.clear();
//
//            //add sdcard
//            if (mContext.getExternalCacheDir() != null) {
//                File file = new File(mContext.getExternalCacheDir() + "/download");
//                try {
//                    Runtime.getRuntime().exec("chmod -R 777 " + mContext.getExternalCacheDir().getAbsolutePath());
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                if (!file.exists())
//                    file.mkdirs();
//                availableDownloadPath.add(file.getAbsolutePath());
//            }
//
//            //add data
//            {
//                File file = new File(mContext.getCacheDir().getAbsolutePath() + "/download");
//                try {
//                    Runtime.getRuntime().exec("chmod -R 777 " + mContext.getCacheDir().getAbsolutePath());
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                if (!file.exists())
//                    file.mkdirs();
//                availableDownloadPath.add(file.getAbsolutePath());
//            }
//
//            //add max free space external disk
//            {
//                List<Storage.SDevice> devices = Storage.getSDeviceList();
//                Storage.SDevice max_device = null;
//                for (Storage.SDevice device : devices) {
//                    if (device.getMediaType() == Storage.SDevice.MEDIA_TYPE.SDCARD)
//                        continue;
//                    if (max_device == null)
//                        max_device = device;
//                    else {
//                        if (Storage.getFreeSpace(max_device, true) < Storage.getFreeSpace(device, true))
//                            max_device = device;
//                    }
//                }
//                if (max_device != null)
//                    availableDownloadPath.add(max_device.getMountPoint());
//            }
//        }
//    }

    @Override
    public List<DownloadTask> getList() throws RemoteException {
        return taskCache.values();
    }

    @Override
    public int getStatus(DownloadTask task) throws RemoteException {
        if (taskCache.containsKey(task._getID())) {
            FileDownloader.DownloadController dc = dcCache.get(task._getID());
            if (dc != null) {
                switch (dc.getStatus()) {
                    case FileDownloader.DownloadController.STATUS_WAITING:
                        return DownloadTask.STATUS_WAITING;
                    case FileDownloader.DownloadController.STATUS_DOWNLOADING:
                        return DownloadTask.STATUS_DOWNLOADING;
                    case FileDownloader.DownloadController.STATUS_PAUSE:
                        return DownloadTask.STATUS_PAUSE;
                    case FileDownloader.DownloadController.STATUS_SUCCESS:
                        return DownloadTask.STATUS_SUCCESS;
                    default:
                        return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_EXIST;
                }
            }
            return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_START;
        }
        return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_EXIST;
    }

    @Override
    public synchronized int start(final DownloadTask task) throws RemoteException {
        FileDownloader.DownloadController dc = null;
        int status = getStatus(task);
        if (status >= 0) {
            switch (status) {
                case DownloadTask.STATUS_PAUSE:
                    dc.resume();
                    return -ErrorCode.EC_SUCCESS;
                default:
                    return status;
            }
        }
        LiteHandlerThread.postOnUiThread(new Runnable() {
            @Override
            public void run() {
                FileDownloader.DownloadController _dc = Netroid.getFileDownload().add(task.save_path, task.download_url, new MyListener(task));
                dcCache.add(task._getID(), _dc);
            }
        });
        taskCache.add(task._getID(), task);
        XServiceManager.getLiteConfigService().saveStringConfig(CONFIG_KEY, new TaskList(taskCache.values()).toJSONString());
        return -ErrorCode.EC_SUCCESS;
    }

    @Override
    public synchronized int pause(DownloadTask task) throws RemoteException {
        if (taskCache.containsKey(task._getID())) {
            FileDownloader.DownloadController dc = dcCache.get(task._getID());
            if (dc != null) {
                dc.pause();
                return -ErrorCode.EC_SUCCESS;
            }
            return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_START;
        }
        return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_EXIST;
    }

    @Override
    public synchronized int cancel(DownloadTask task) throws RemoteException {
        if (taskCache.containsKey(task._getID())) {

            LogUtils.i("IOP", "************************downloader2 cancel " + task.save_path);
            FileDownloader.DownloadController dc = dcCache.get(task._getID());
            if (dc != null) {
                dc.discard();
                removeTask(task, true);
                return -ErrorCode.EC_SUCCESS;
            }
            return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_START;
        }
        return -ErrorCode.EC_LITEDOWNLOADER_TASK_NOT_EXIST;
    }

    @Override
    public void addListener(ILiteDownloadServiceListener l) throws RemoteException {
        synchronized (callbacks) {
            if (l != null) {
                IBinder binder = l.asBinder();
                CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i = new CoocaaService.AIDLInterface<ILiteDownloadServiceListener>(
                        binder, l);
                callbacks.add(i);
            }
        }
    }

    @Override
    public void removeListener(ILiteDownloadServiceListener l) throws RemoteException {
        synchronized (callbacks) {
            if (l != null) {
                IBinder binder = l.asBinder();
                for (CoocaaService.AIDLInterface<ILiteDownloadServiceListener> i : callbacks) {
                    if (i.binder == binder) {
                        callbacks.remove(i);
                        break;
                    }
                }
            }
        }
    }

    private void removeTask(DownloadTask task, boolean removeFile) {
        dcCache.remove(task._getID());
        taskCache.remove(task._getID());
        try {
            XServiceManager.getLiteConfigService().saveStringConfig(CONFIG_KEY, new TaskList(taskCache.values()).toJSONString());
        } catch (RemoteException e) {
        }
        if (removeFile) {
            LogUtils.i("IOP", "************************downloader2 removeTask removefile " + task.save_path);

            File file = new File(task.save_path);
            if (file.exists())
                file.delete();
        }
    }

    @Override
    public String getSavePath() throws RemoteException {
        String path = _getSavePath();
        return path;//availableDownloadPath.get(0);
    }

    private String _getSavePath() {
        File file = mContext.getExternalCacheDir();
        if (file != null && Storage.getFreeSpace(file.getAbsolutePath(), true) > 50 * 1024 * 1024) {
            file = new File(file.getAbsolutePath() + "/download");
            try {
                Runtime.getRuntime().exec("chmod -R 777 " + mContext.getExternalCacheDir().getAbsolutePath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            file = new File(mContext.getCacheDir().getAbsolutePath() + "/download");
            try {
                Runtime.getRuntime().exec("chmod -R 777 " + mContext.getCacheDir().getAbsolutePath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (!file.exists())
            file.mkdirs();
        try {
            Runtime.getRuntime().exec("chmod -R 777 " + file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file.getAbsolutePath();
//
//
//
//
//        List<Storage.SDevice> list = Storage.getSDeviceList();
//        Storage.SDevice maxFreeDevice = null;
//        for (Storage.SDevice device : list)
//        {
//            if (device.getMediaType() == Storage.SDevice.MEDIA_TYPE.SDCARD)
//            {
//                if (Storage.getSDCardFreeSpace() > fileLength + 100 * 1024 * 1024)
//                    return Storage.getSDCardPath("coocaa_app/download/");
//                continue;
//            } else
//            {
//                if (maxFreeDevice == null)
//                    maxFreeDevice = device;
//                else
//                {
//                    if (Storage.getFreeSpace(maxFreeDevice, false) < Storage.getFreeSpace(device,
//                            false))
//                        maxFreeDevice = device;
//                }
//            }
//        }
//
//        if (Storage.getInternalMemoryFreeSpace() - Storage.getReservedMemory()
//                > fileLength * 2 + 100 * 1024 * 1024)
//        {
//            Storage.setReservedMemory(fileLength);
//            return Storage.getInternalMemoryPath("coocaa_app/download/");
//        }
//
//        if (maxFreeDevice != null && Storage.getFreeSpace(maxFreeDevice, false) > fileLength + 100 * 1024 * 1024)
//            return Storage.getSDevicePath(maxFreeDevice, "coocaa_app/download/");
    }
}
